import { gameController } from "./gameController";
import Shape from "./Shape";
import ShapeItem from "./ShapeItem";
import ShapeManager from "./shapeManager";
import BaseComp from "./ui/baseComp";
import { blink, debugLog, getMaxInArr, getMinInArr } from "./utils/util";

const {ccclass, property} = cc._decorator;

@ccclass
export default class Game extends BaseComp {

    @property(cc.Prefab)
    gridPrefab: cc.Prefab = null;

    @property(cc.Node)
    mapRoot: cc.Node = null;

    @property([cc.Prefab])
    shapePrefabs: cc.Prefab[] = [];

    @property({type: cc.Integer})
    row: number = 30;
    @property({type: cc.Integer})
    col: number = 15;
    @property(cc.SpriteAtlas)
    frames: cc.SpriteAtlas = null;

    public curGoDownShape: Shape = null;
    private _shapeManager: ShapeManager = null;
    public downSpeed: number = 0.3;
    // private downMaxSpeed: number = 0.1;
    private isStop: boolean = false;

    public hasAccelate: boolean = false;
    /** 地图数据 驱动地图view */
    private mapModel: cc.Node[][] = [];

    async onLoad () {
        gameController.game = this;
        this._initMap();
        this._init();
        // for(let i = 0; i < 4; i++) {
        //     await new Promise((resolve) => {
        //         this.scheduleOnce(() => {
        //             this.goDown();
        //             resolve(null);
        //         },this.downSpeed);
        //     })
        // }
        this.schedule(this.goDown,this.downSpeed);

        cc.debug.setDisplayStats(false);
    }

    onEnable(): void {
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.keyDown, this);
        cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.keyUp, this);     
    }

    onDisable(): void {
        cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.keyDown, this);
        cc.systemEvent.off(cc.SystemEvent.EventType.KEY_UP, this.keyUp, this);
    }

    private keyDown(event: cc.Event.EventKeyboard): void {
        switch(event.keyCode) {
            case cc.macro.KEY.left:
                debugLog("left");
                this.goLeft();
                break;
            case cc.macro.KEY.right:
                debugLog("right");
                this.goRight();
                break;
            case cc.macro.KEY.down:
                debugLog("down");
                this.acceletaDown();
                break;
            case cc.macro.KEY.space:
                this.rotateShape();
                break;        
            case cc.macro.KEY.s:
                this.isStop = !this.isStop;
                if(this.isStop) {
                    this.unschedule(this.goDown);
                } else {
                    this.schedule(this.goDown,this.downSpeed);
                }
                break;        
        }
    }

    private keyUp(event: cc.Event.EventKeyboard): void {

    }

    

    private _init(): void {
        this._shapeManager = new ShapeManager();
        gameController.shapeManager = this._shapeManager;
        gameController.row = this.row;
        gameController.col = this.col;
        gameController.init();

        this._shapeManager.init(this.viewMap['shapes'],this.viewMap['shapeBorn'],this.shapePrefabs,this.viewMap['map'],this.frames);
        this._shapeManager.map = this.mapModel;
        this.curGoDownShape = this._shapeManager.createShape();
    }

    public createShape(): void {
        this.curGoDownShape = this._shapeManager.prepareNextShape();
    }

    public recoverNormalSchedule() {
        this.unschedule(this.goDown);
        this.downSpeed = 0.3;
        this.schedule(this.goDown,this.downSpeed);
    }
    
    private _initMap(): void {
        this.mapModel = [];
        for(let i = 0; i < this.row; i++) {
            this.mapModel[i] = [];
            for(let j = 0; j < this.col; j++) {
                const gridNode = cc.instantiate(this.gridPrefab);
                this.mapRoot.addChild(gridNode);
                this.mapModel[i][j] = null;
            }
        }
        gameController.gameMap = this.mapModel;
    }

    public goDown(): void {
        if(this.curGoDownShape) {
            this.curGoDownShape.goDown();
        }
    }

    public goLeft(): void {
        if(this.curGoDownShape) {
            console.log("形状左移");
            this.curGoDownShape.goLeft();
        }
    }

    public goRight(): void {
        if(this.curGoDownShape) {
            this.curGoDownShape.goRight();
        }
    }

    public acceletaDown(): void {
        if(this.hasAccelate) return;
        this.hasAccelate = true;
        /** 直接下落到目的地 */
        this.downSpeed = 0.01;
        this.unschedule(this.goDown);
        this.schedule(this.goDown,this.downSpeed);
        console.log('downSpeed is ',this.downSpeed);
    }

    public rotateShape(): void {
        if(this.curGoDownShape) {
            this.curGoDownShape.rotate();
        }
    }

    /**
     * 检查是否可以进行消除操作 把消除的行返回
     * @returns number[]
     */
    public checkCanCleanUp(): number[] {
        let res = [];
        for(let i = this.row - 1; i >= 0; i--) {
            const isAllColHasNode = gameController.gameMap[i].every(item => item);
            isAllColHasNode && res.push(i);
        }
        return res;
    }

    
    /**
     * 消除操作
     * @param  {number[]} rows 消除的行
     * @returns Promise<void>
     */
    public async clearUp(rows: number[]): Promise<void> {
        rows.sort((a,b) => a > b ? -1 : a === b ? 0 : 1);
        // 从最底下行开始消除并且移动该行以上的所有节点
        for(let row of rows) {
            for(let itemNode of gameController.gameMap[row]) {
                if(!itemNode) continue;

                const shapeComp = itemNode.parent.getComponent(Shape);
                // 每一个节点blink了
                await blink(itemNode);
                const uuid = itemNode.uuid;
                // 清除节点
                itemNode.destroy();
                shapeComp.cleanUp(uuid);
            }
        } 
        console.log('After clear map is ',gameController.stopedNodeMap);

        const totalWaitDownNodes: {[key: string]: cc.Node[]} = {};

        const maxClearRow = getMaxInArr(rows);
        const minClearRow = getMinInArr(rows);

        for(let index = 0; index < gameController.row; index++) {
            const item = gameController.gameMap[index];
            if(index > maxClearRow) break;

            if(index < minClearRow || (index > minClearRow && index < maxClearRow && !rows.includes(index))) {
                totalWaitDownNodes[index] = item;
            }
        }
        
        const waitDownNodes = Object.values(totalWaitDownNodes);
        let lastIndex = Object.values(totalWaitDownNodes).length - 1;

        // 遍历地图上的节点 从下向上遍历
        while(lastIndex >= 0) {
            const tempNodeArr = waitDownNodes[lastIndex];
            tempNodeArr.forEach((itemNode: cc.Node,colIndex) => {
                if(!itemNode) return
                if(itemNode.parent === this.curGoDownShape.node) return;
                
                const shapeComp = itemNode.getComponent(ShapeItem);
                shapeComp.goDown(rows,minClearRow,maxClearRow);
            });
            lastIndex--;
        }
    }

    start () {

    }

    // update (dt) {}
}
